//
// Created by 王筱童 on 2022/5/9.
//
#include "others.h"
#include "redis_connection.h"
#include "redis_server.h"
#include <iostream>
#include <experimental/source_location>

asio::awaitable<void> redis_connection::start() {
    try {
#ifdef TEST
        std::cout<<"connection start running"<<std::endl;
#endif
        for (;!close_spawn;) {
            std::string data = co_await read_data();
            std::string result = co_await exec_command(data);
            if(!close_spawn)
                co_await write_result(result);
        }
    }
    catch (const std::exception &ec) {
        server->close_conn(index);
        std::cerr << "error: " << std::experimental::source_location::current().function_name() << " " << ec.what()
                  << std::endl;
    }
}

asio::awaitable<std::string> redis_connection::read_data() {
    std::string head(sizeof(uint64_t), '\0');
    co_await asio::async_read(socket, asio::buffer(head, sizeof(uint64_t)), asio::use_awaitable);
    auto[sz, tail]=deserialize_head(head);
    std::string body(sz, '\0');
    co_await asio::async_read(socket, asio::buffer(body, sz), asio::use_awaitable);
#ifdef TEST
    std::cout << "receive data :" + body + "\n";
#endif
    co_return body;
}

asio::awaitable<void> redis_connection::write_result(const std::string &result) {
    std::string data = serialize(result);
    co_await asio::async_write(socket, asio::buffer(data, data.size()), asio::use_awaitable);
#ifdef TEST
    std::cout << "write data :" + data + "\n";
#endif
}

asio::awaitable<std::string> redis_connection::exec_command(const std::string &data) {
#ifdef TEST
    std::cout << std::string("running in") + std::experimental::source_location::current().function_name() + "\n";
    std::cout << "argument data:" + data << std::endl;
#endif
    std::string str = trim(data);
    std::vector<std::string> strings = split(str, ' ');
    if (strings.empty()) {
        co_return nil;
    }
    co_return server->exec_command(strings[0], std::vector<std::string>(strings.begin() + 1, strings.end()), index);
}

redis_connection::redis_connection(asio::ip::tcp::socket &&_sock, redis_server *_server, std::size_t _index) : socket(
        std::move(_sock)), server(_server), index(_index),db_index(0) {

}

void redis_connection::close_coro() {
    close_spawn= true;
}

asio::ip::tcp::socket &redis_connection::get_socket() {
    return socket;
}
